﻿using HalconDotNet;
using MvCamCtrl.NET;
using MvCamCtrl.NET.CameraParams;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;

namespace CCSFeederCameraUI2.Services
{
    internal class CameraService : ICameraService
    {
        private int nRet = CErrorDefine.MV_OK;
        public bool m_bIsDeviceOpen { get; set; }       // ch:设备打开状态 | en:Is device open
        public ActionRef1<IntPtr, MV_FRAME_OUT_INFO_EX> ImageCallbackFunc { get; set; }
        public ConcurrentQueue<HObject> ImageQueue { get; set; }

        private CCamera m_MyCamera = new CCamera();
        private cbOutputExdelegate ImageCallback;

        public void CloseCamera()
        {
            try
            {
                // ch:停止抓图 | en:Stop grabbing
                nRet = m_MyCamera.StopGrabbing();
                // ch:关闭设备 | en:Close device
                nRet = m_MyCamera.CloseDevice();
                // ch:销毁设备 | en:Destroy device
                nRet = m_MyCamera.DestroyHandle();
                m_bIsDeviceOpen = false;
            }
            catch { }
        }
        public bool OpenCamera(string cameraIP)
        {
            try
            {
                int nRet = CErrorDefine.MV_OK;
                m_MyCamera = new CCamera();
                List<CCameraInfo> ltDeviceList = new List<CCameraInfo>();

                // ch:枚举设备 | en:Enum device
                nRet = CSystem.EnumDevices(CSystem.MV_GIGE_DEVICE | CSystem.MV_USB_DEVICE, ref ltDeviceList);
                if (nRet != CErrorDefine.MV_OK)
                {
                    Debug.WriteLine("Enum device failed:{0:x8}", nRet);
                    return false;
                }
                Debug.WriteLine("Enum device count : " + Convert.ToString(ltDeviceList.Count));
                if (ltDeviceList.Count == 0)
                {
                    return false;
                }

                int nDevIndex = -1;
                // ch:打印设备信息 en:Print device info
                for (int i = 0; i < ltDeviceList.Count; i++)
                {
                    if (CSystem.MV_GIGE_DEVICE == ltDeviceList[i].nTLayerType)
                    {
                        CGigECameraInfo cGigEDeviceInfo = (CGigECameraInfo)ltDeviceList[i];

                        uint nIp1 = ((cGigEDeviceInfo.nCurrentIp & 0xff000000) >> 24);
                        uint nIp2 = ((cGigEDeviceInfo.nCurrentIp & 0x00ff0000) >> 16);
                        uint nIp3 = ((cGigEDeviceInfo.nCurrentIp & 0x0000ff00) >> 8);
                        uint nIp4 = (cGigEDeviceInfo.nCurrentIp & 0x000000ff);

                        Debug.WriteLine("[device " + i.ToString() + "]:");
                        Debug.WriteLine("  DevIP:" + nIp1 + "." + nIp2 + "." + nIp3 + "." + nIp4);
                        if ($"{nIp1}.{nIp2}.{nIp3}.{nIp4}" == cameraIP)
                        {
                            nDevIndex = i;
                        }
                    }
                    else if (CSystem.MV_USB_DEVICE == ltDeviceList[i].nTLayerType)
                    {
                        CUSBCameraInfo cUsb3DeviceInfo = (CUSBCameraInfo)ltDeviceList[i];

                        Debug.WriteLine("[device " + i.ToString() + "]:");
                        Debug.WriteLine("  SerialNumber:" + cUsb3DeviceInfo.chSerialNumber);
                        if ($"{cUsb3DeviceInfo.chSerialNumber}" == cameraIP)
                        {
                            nDevIndex = i;
                        }
                    }
                }
                if (nDevIndex >= 0)
                {
                    // ch:获取选择的设备信息 | en:Get selected device information
                    CCameraInfo stDevice = ltDeviceList[nDevIndex];
                    // ch:创建设备 | en:Create device
                    nRet = m_MyCamera.CreateHandle(ref stDevice);
                    if (CErrorDefine.MV_OK != nRet)
                    {
                        Debug.WriteLine("Create device failed:{0:x8}", nRet);
                        return false;
                    }
                    // ch:打开设备 | en:Open device
                    nRet = m_MyCamera.OpenDevice();
                    if (CErrorDefine.MV_OK != nRet)
                    {
                        Debug.WriteLine("Open device failed:{0:x8}", nRet);
                        return false;
                    }
                 
                    // ch:设置采集模式：连续
                    nRet = m_MyCamera.SetEnumValue("AcquisitionMode", (uint)MV_CAM_ACQUISITION_MODE.MV_ACQ_MODE_CONTINUOUS);
                    if (CErrorDefine.MV_OK != nRet)
                    {
                        Debug.WriteLine("Set AcquisitionMode failed:{0:x8}", nRet);
                        return false;
                    }
                    // ch:设置触发模式为on
                    nRet = m_MyCamera.SetEnumValue("TriggerMode", (uint)MV_CAM_TRIGGER_MODE.MV_TRIGGER_MODE_OFF);
                    if (CErrorDefine.MV_OK != nRet)
                    {
                        Debug.WriteLine("Set TriggerMode failed:{0:x8}", nRet);
                        return false;
                    }
                    // ch:设置触发源：line0
                    nRet = m_MyCamera.SetEnumValue("TriggerSource", (uint)MV_CAM_TRIGGER_SOURCE.MV_TRIGGER_SOURCE_LINE0);
                    if (CErrorDefine.MV_OK != nRet)
                    {
                        Debug.WriteLine("Set TriggerSource failed:{0:x8}", nRet);
                        return false;
                    }

                    // ch:注册回调函数
                    ImageCallback = new cbOutputExdelegate(ImageCallbackFunc);
                    nRet = m_MyCamera.RegisterImageCallBackEx(ImageCallback, IntPtr.Zero);
                    if (CErrorDefine.MV_OK != nRet)
                    {
                        Debug.WriteLine("Register image callback failed!");
                        return false;
                    }
                }
                else
                {
                    Debug.WriteLine($"未找到\"{cameraIP}\"设备");
                    return false;
                }
                m_bIsDeviceOpen = true;
                return true;
            }
            catch (HalconException ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }

        public bool StartGrabe()
        {
            try
            {
                // ch:开启抓图 || en: start grab image
                nRet = m_MyCamera.StartGrabbing();
                if (CErrorDefine.MV_OK != nRet)
                {
                    Debug.WriteLine("Start grabbing failed:{0:x8}", nRet);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }

        public bool StopGrabe()
        {
            try
            {
                // ch:停止抓图 | en:Stop grabbing
                nRet = m_MyCamera.StopGrabbing();
                if (CErrorDefine.MV_OK != nRet)
                {
                    Debug.WriteLine("Stop grabbing failed:{0:x8}", nRet);
                    return false;
                }
                return true;
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.Message);
                return false;
            }
        }

        public bool SetTriggerMode(uint triggerMode)
        {
            // ch:设置触发模式为on
            nRet = m_MyCamera.SetEnumValue("TriggerMode", triggerMode);
            if (CErrorDefine.MV_OK != nRet)
            {
                Debug.WriteLine("Set TriggerMode failed:{0:x8}", nRet);
                return false;
            }
            else
                return true;
        }
        public bool SetExposureTime(float time)
        {
            nRet = m_MyCamera.SetFloatValue("ExposureTime", time);
            if (CErrorDefine.MV_OK != nRet)
            {
                Console.WriteLine("Set ExposureTime failed:{0:x8}", nRet);
                return false;
            }
            return true;
        }
        public bool SetFrameRate(float rate)
        {
            nRet = m_MyCamera.SetFloatValue("AcquisitionFrameRate", rate);
            if (CErrorDefine.MV_OK != nRet)
            {
                Console.WriteLine("Set AcquisitionFrameRate failed:{0:x8}", nRet);
                return false;
            }
            return true;
        }
    }
}
